/*
 * Copyright (C) 2025 ameise <ameise.wang@gmail.com> - All Rights Reserved
 *
 * This file is part of e3log.
 *
 * e3log is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * e3log is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with e3log. If not, see <https://www.gnu.org/licenses/>.
 */

package e3log

import (
	"github.com/fatih/color"
	"sync"
)

type LogMarshaller interface {
	E3LogMarshall() string
}

var gLogEventPool sync.Pool

func init() {
	gLogEventPool = sync.Pool{
		New: func() any {
			return &LogEvent{
				buf: make([]byte, 0, 512),
			}
		},
	}
}

func takeLogEvent(cb logCallBack, enc iEncoder, lv Level, color *color.Color) *LogEvent {
	evt := gLogEventPool.Get().(*LogEvent)
	evt.buf = evt.buf[:0]
	evt.enc = enc
	evt.cb = cb
	evt.lv = lv
	evt.color = color
	evt.buf = enc.begin(evt.buf)
	return evt
}

func freeLogEvent(evt *LogEvent) {
	evt.enc = nil
	evt.cb = nil
}

type LogEvent struct {
	buf   []byte
	enc   iEncoder
	cb    logCallBack
	lv    Level
	color *color.Color
}

func (ts *LogEvent) Any(key string, val any) *LogEvent {
	ts.Str(key, formatReflect(val))
	return ts
}

func (ts *LogEvent) Anys(key string, vals ...any) *LogEvent {
	vs := make([]string, len(vals))
	for i, v := range vals {
		vs[i] = formatReflect(v)
	}
	ts.Strs(key, vs...)
	return ts
}

func (ts *LogEvent) Str(key string, val string) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendStr(ts.buf, key, val)
	return ts
}

func (ts *LogEvent) Strs(key string, vals ...string) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendStrs(ts.buf, key, vals)
	return ts
}

func (ts *LogEvent) Err(val error) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendErr(ts.buf, val)
	return ts
}

func (ts *LogEvent) Errs(vals ...error) *LogEvent {
	if ts == nil {
		return nil
	}
	if len(vals) == 0 {
		return ts
	}
	ts.buf = ts.enc.appendErrs(ts.buf, vals)
	return ts
}

func (ts *LogEvent) Int(key string, val int) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendInt(ts.buf, key, val)
	return ts
}

func (ts *LogEvent) Ints(key string, vals ...int) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendInts(ts.buf, key, vals)
	return ts
}

func (ts *LogEvent) Int8(key string, val int8) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendInt8(ts.buf, key, val)
	return ts
}

func (ts *LogEvent) Int8s(key string, vals ...int8) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendInt8s(ts.buf, key, vals)
	return ts
}

func (ts *LogEvent) Int16(key string, val int16) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendInt16(ts.buf, key, val)
	return ts
}

func (ts *LogEvent) Int16s(key string, vals ...int16) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendInt16s(ts.buf, key, vals)
	return ts
}

func (ts *LogEvent) Int32(key string, val int32) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendInt32(ts.buf, key, val)
	return ts
}

func (ts *LogEvent) Int32s(key string, vals ...int32) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendInt32s(ts.buf, key, vals)
	return ts
}

func (ts *LogEvent) Int64(key string, val int64) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendInt64(ts.buf, key, val)
	return ts
}

func (ts *LogEvent) Int64s(key string, vals ...int64) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendInt64s(ts.buf, key, vals)
	return ts
}

func (ts *LogEvent) Uint(key string, val uint) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendUint(ts.buf, key, val)
	return ts
}

func (ts *LogEvent) Uints(key string, vals ...uint) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendUints(ts.buf, key, vals)
	return ts
}

func (ts *LogEvent) Uint8(key string, val uint8) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendUint8(ts.buf, key, val)
	return ts
}

func (ts *LogEvent) Uint8s(key string, vals ...uint8) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendUint8s(ts.buf, key, vals)
	return ts
}

func (ts *LogEvent) Uint16(key string, val uint16) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendUint16(ts.buf, key, val)
	return ts
}

func (ts *LogEvent) Uint16s(key string, vals ...uint16) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendUint16s(ts.buf, key, vals)
	return ts
}

func (ts *LogEvent) Uint32(key string, val uint32) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendUint32(ts.buf, key, val)
	return ts
}

func (ts *LogEvent) Uint32s(key string, vals ...uint32) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendUint32s(ts.buf, key, vals)
	return ts
}

func (ts *LogEvent) Uint64(key string, val uint64) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendUint64(ts.buf, key, val)
	return ts
}

func (ts *LogEvent) Uint64s(key string, vals ...uint64) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendUint64s(ts.buf, key, vals)
	return ts
}

func (ts *LogEvent) Float32(key string, precision int, val float32) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendFloat32(ts.buf, key, precision, val)
	return ts
}

func (ts *LogEvent) Float32s(key string, precision int, vals ...float32) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendFloat32s(ts.buf, key, precision, vals)
	return ts
}

func (ts *LogEvent) Float64(key string, precision int, val float64) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendFloat64(ts.buf, key, precision, val)
	return ts
}

func (ts *LogEvent) Float64s(key string, precision int, vals ...float64) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendFloat64s(ts.buf, key, precision, vals)
	return ts
}

func (ts *LogEvent) Bool(key string, val bool) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendBool(ts.buf, key, val)
	return ts
}

func (ts *LogEvent) Bools(key string, vals ...bool) *LogEvent {
	if ts == nil {
		return nil
	}
	ts.buf = ts.enc.appendBools(ts.buf, key, vals)
	return ts
}

func (ts *LogEvent) Object(val LogMarshaller) *LogEvent {
	if ts == nil {
		return nil
	}
	if val == nil {
		return ts
	}
	ts.buf = ts.enc.appendObject(ts.buf, val)
	return ts
}

func (ts *LogEvent) Objects(vals ...LogMarshaller) *LogEvent {
	if ts == nil {
		return nil
	}
	if len(vals) == 0 {
		return ts
	}
	ts.buf = ts.enc.appendObjects(ts.buf, vals)
	return ts
}

func (ts *LogEvent) Println() {
	if ts == nil {
		return
	}
	ts.buf[len(ts.buf)-1] = '}'
	ts.buf = append(ts.buf, '\n')
	ts.cb(ts)
}

func (ts *LogEvent) Print() {
	if ts == nil {
		return
	}
	ts.buf[len(ts.buf)-1] = '}'
	ts.cb(ts)
}

func (ts *LogEvent) Format() string {
	if ts == nil {
		return ""
	}
	ts.buf[len(ts.buf)-1] = '}'
	ts.buf = append(ts.buf, '\n')
	return logBytesToString(ts.buf)
}
